"use strict"

/**
 * 网络爬虫接口模块
 * sunny
 *  
 */
///<reference path="index.d.ts" />
const cheerio = require("cheerio");
const http = require("http");
const https = require("https");
const net = require('net');
const urlp = require('url');
const BufferHelper = require("bufferhelper");
const iconv = require("iconv-lite");
const urlencode = require("urlencode");
const deasync = require('deasync');

var Spider = function () {
    this.headers = {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/52.0.2743.116 Chrome/52.0.2743.116 Safari/537.36",
        "Provider": "audit.yonyou.com/tax",
    };
    // this.jar = request.jar();
    this.encode = "utf8";
    this.version = "1.0.0";
    this.name = "crawler spider support";
    this.url = "";
    this.debug = false;
    this.raw = false; // 是否保存纯数据（二进制）
    this.timeout = 600000; //默认超时时间设置为10分钟
    this.http_hander = http;
};
var response_fn = function (response, self, cb) {
    var bufferHelper = new BufferHelper();
    var encoding = self.encode;
    response.on("data", (data) => {
        bufferHelper.concat(data);
    });
    response.on("error", (err) => {
        console.error(err);
    });
    response.on('end', () => {
        var _data;
        if (self.raw) {
            cb(bufferHelper.toBuffer());
        }
        else {
            if (typeof encoding != 'undefined' && encoding !== null) {
                _data = iconv.decode(bufferHelper.toBuffer(), encoding);
            } else {
                _data = iconv.decode(bufferHelper.toBuffer(), 'utf-8');
            }
            cb(_data);
        }
    });
};

var minx = function (dest, src) {
    for (var k in src) {
        if (src.hasOwnProperty(k)) {
            dest[k] = src[k];
        }
    }
    return dest;
};

var process_headers = function (spider, response, url) {
    if (response)
        spider.headers = minx(spider.headers, response.headers);
    var setcookie = response.headers["set-cookie"];
    if (setcookie) {
        var cs = [];
        setcookie.forEach(
            function (cookiestr) {
                cs.push(cookiestr);
            }
        );
        spider.headers["Cookie"] = cs.join("; ");
    }
    if (url) {
        spider.headers["Referer"] = url;
    }
    delete spider.headers["Content-Length"];
    if (spider.debug) {
        console.log("-------------------------");
        console.log("raw: " + spider.raw);
        console.log("encode: " + spider.encode);
        console.log("timeout: " + spider.timeout);
        console.log("version: " + spider.version);
        console.log("name: " + spider.name);
        console.log("-------------------------");
        console.dir(spider.headers);
        console.log("-------------------------");
    }
};

/**
 *Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.tufieping.com:8080',
  port: '8080',
  hostname: 'www.tufieping.com',
  hash: null,
  search: '?xxxx=yyyy&mmm=nnnn',
  query: 'xxxx=yyyy&mmm=nnnn',
  pathname: '/test',
  path: '/test?xxxx=yyyy&mmm=nnnn',
  href: 'http://www.tufieping.com:8080/test?xxxx=yyyy&mmm=nnnn' }

 */

var do_get = function (self, url, cb) {
    if (/https/i.test(url)) {
        self.http_hander = https;
    }
    var urlprop = urlp.parse(url);
    urlp.parse(url);
    var _headers = {};
    minx(_headers, self.headers);
    var cs = self.headers["Set-Cookie"];
    if (!cs && cs != undefined) {
        _headers["Cookie"] = cs;
    }
    delete _headers["content-length"];
    // console.dir(_headers);
    var options = {
        method: 'GET',
        host: urlprop.hostname,
        port: urlprop.port,
        path: urlprop.path,
        headers: _headers
    };
    const req = self.http_hander.request(options, function (response) {
        process_headers(self, response, url);
        response_fn(response, self, cb);
    });
    req.setTimeout(self.timeout);
    // req.write("");
    req.end();
};

var do_post = function (self, url, cb, post_data) {
    if (/https/i.test(url)) {
        self.http_hander = https;
    }
    var post_datas = [];
    for (var k in post_data) {
        if (post_data.hasOwnProperty(k)) {
            var v = post_data[k];
            post_datas.push(k + "=" + urlencode.encode(v, self.encode));
        }
    }
    var postData = post_datas.join("&");
    var c_l = postData.length;
    var urlprop = urlp.parse(url);
    var _headers = {};
    minx(_headers, self.headers);
    _headers['Content-Type'] = 'application/x-www-form-urlencoded';
    _headers["Content-Length"] = c_l;
    var options = {
        method: 'POST',
        host: urlprop.hostname,
        port: urlprop.port,
        path: urlprop.path,
        headers: _headers
    };
    //console.dir(_headers);
    const req = self.http_hander.request(options, function (response) {
        process_headers(self, response, url);
        response_fn(response, self, cb);
    });
    req.write(postData);
    req.setTimeout(self.timeout);
    req.end();
};

// 异步get
Spider.prototype.get = function (url, cb) {
    do_get(this, url, cb);
};

// 同步get
Spider.prototype.getSync = function (url) {
    try {
        var finished = false, result;
        do_get(this, url, function (data, err) {
            if (err) {
                result = err;
                finished = true;
            } else {
                result = data;
                finished = true;
            }
        });
        while (!finished) {
            deasync.runLoopOnce();
        }
        return result;
    } catch (e) {
        console.error(e);
        return "";
    }
};

// 异步post
Spider.prototype.post = function (url, post_data, cb) {
    do_post(this, url, cb, post_data);
};

// 同步post
Spider.prototype.postSync = function (url, post_data) {
    try {
        var finished = false, result;
        do_post(this, url, function (data, err) {
            if (err) {
                result = err;
                finished = true;
            } else {
                result = data;
                finished = true;
            }
        }, post_data);
        while (!finished) {
            deasync.runLoopOnce();
        }
        return result;
    } catch (e) {
        console.error(e);
        return "";
    }
};

exports = module.exports = Spider; 